package cn.leaves.wb.db.dao.jdbc;

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationTargetException;
import java.sql.Timestamp;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

import javax.persistence.Table;
import javax.persistence.Transient;

import org.springframework.util.StringUtils;

public class SQLGenerator {
	private String tableName;
	private Object beanInstance;
	private String[] reflusedProperties;
	private String[] propertyNames = null;
	private Object[] propertyValues = null;

	public SQLGenerator(Object beanInstance, String... reflusedProperties)
			throws IllegalArgumentException, IntrospectionException, IllegalAccessException, InvocationTargetException {
		this.beanInstance = beanInstance;
		this.reflusedProperties = reflusedProperties;
		initBeansPropertyDescriptor();
	}

	private void initBeansPropertyDescriptor() throws IntrospectionException, IllegalArgumentException,
			IllegalAccessException, InvocationTargetException {
		Class<?> clazz = beanInstance.getClass();
		if (beanInstance != null) {
			initTableName(beanInstance.getClass());
			BeanInfo bi = Introspector.getBeanInfo(beanInstance.getClass());
			List<String> reflusedList = new ArrayList<String>();
			reflusedList.add("class");
			if (reflusedProperties != null) {
				reflusedList.addAll(Arrays.asList(reflusedProperties));
			}
			PropertyDescriptor[] pds = bi.getPropertyDescriptors();
			if (pds != null) {
				int index = 0;
				propertyNames = new String[pds.length];
				propertyValues = new Object[pds.length];
				for (PropertyDescriptor pd : pds) {
					Annotation[] propertyAnnotations = null;
					if (propertyAnnotations == null) {
						pd.getWriteMethod().getAnnotations();
					}
					if (propertyAnnotations == null) {
						pd.getReadMethod().getAnnotations();
					}
					if (propertyAnnotations == null) {
						try {
							propertyAnnotations = clazz.getField(pd.getName()).getAnnotations();
						} catch (SecurityException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						} catch (NoSuchFieldException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
					if (propertyAnnotations != null) {
						for (Annotation annotation : propertyAnnotations) {
							if(annotation instanceof Transient) {
								continue;
							}
						}
					}
					if (!reflusedList.contains(pd.getName()) && index < pds.length) {
						propertyNames[index] = pd.getName();
						Object propertyValue = pd.getReadMethod().invoke(beanInstance);
						propertyValues[index] = translateValueType(pd.getPropertyType(), propertyValue);
						index++;
					}
				}
				propertyNames = Arrays.copyOf(propertyNames, index);
				propertyValues = Arrays.copyOf(propertyValues, index);
			}
		}
	}

	private void initTableName(Class<?> clazz) {
		Table table = clazz.getAnnotation(Table.class);
		if (table != null) {
			tableName = table.name();
		} else {
			tableName = clazz.getSimpleName().toLowerCase();
		}
	}

	/**
	 * 数据类型转换
	 * 
	 * @param clazz
	 * @param value
	 * @return
	 */
	private Object translateValueType(Class<?> clazz, Object value) {
		if (clazz.isAssignableFrom(Date.class)) {
			Date dateInstance = (Date) value;
			return new Timestamp(dateInstance.getTime());
		}
		return value;
	}

	/**
	 * @param instance
	 * @param tableName
	 * @param reflusedProperties
	 * @return
	 * @throws IntrospectionException
	 * @throws IllegalArgumentException
	 * @throws IllegalAccessException
	 * @throws InvocationTargetException
	 */
	public String buildInsertSql() throws IntrospectionException, IllegalArgumentException, IllegalAccessException,
			InvocationTargetException {
		StringBuffer sqlBuffer = new StringBuffer();
		if (propertyNames != null) {
			sqlBuffer.append("insert into ");
			sqlBuffer.append(tableName);
			sqlBuffer.append("(");
			sqlBuffer.append(StringUtils.arrayToDelimitedString(propertyNames, ","));
			sqlBuffer.append(") values(");
			String[] spitString = new String[propertyNames.length];
			Arrays.fill(spitString, "?");
			sqlBuffer.append(StringUtils.arrayToDelimitedString(spitString, ","));
			sqlBuffer.append(")");
			return sqlBuffer.toString();
		}
		return null;
	}

	public Object[] getValues() {
		return propertyValues;
	}

}
